package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.constant.ImgCodeConstants;
import cn.itsource.ymcc.domain.Login;
import cn.itsource.ymcc.domain.User;
import cn.itsource.ymcc.exception.GlobalException;
import cn.itsource.ymcc.mapper.UserMapper;
import cn.itsource.ymcc.openfeign.UaaOpenFeign;
import cn.itsource.ymcc.result.JsonResult;
import cn.itsource.ymcc.service.IUserService;
import cn.itsource.ymcc.util.AssertUtil;
import cn.itsource.ymcc.util.BitStatesUtils;
import cn.itsource.ymcc.vo.RegisterVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author zongchangjiang
 * @since 2023-07-25
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private UaaOpenFeign uaaOpenFeign;

    /**
     * 注册 就是保存
     * 事务
     *    ACID
     *        原子性
     *        一致性
     *        隔离性
     *        持久性
     *  出现了两次事务
     *     一次是本地
     *     一次是远程
     *  分布式事务
     *
     *
     * @param registerVo
     * @return
     */
    @Override
//    @Transactional//它只能管自己  管不了openfeign
    @GlobalTransactional//开启全局事务
    public JsonResult register(RegisterVo registerVo) {
        String key = ImgCodeConstants.IMG_CODE_REGISTER_PHONE_KEY + registerVo.getMobile();
        //校验
        //优先判断是否已经过期
        AssertUtil.isTrue(redisTemplate.hasKey(key),"短信验证码已过期");
        //判断 输入的验证码和redis的验证码是否一致
        String code = redisTemplate.opsForValue().get(key).toString();
        AssertUtil.isTrue(code.equalsIgnoreCase(registerVo.getSmsCode()),"短信验证码输入错误");
        //判断用户是否已经存在
        User phone = baseMapper.selectOne(new QueryWrapper<User>().eq("phone", registerVo.getMobile()));
        AssertUtil.isNull(phone,"该手机已被注册");

        Long loginId = saveLogin(registerVo);//远程调用成功

        saveUser(registerVo, loginId);//本地保存失败
        return JsonResult.success();
    }

    private void saveUser(RegisterVo registerVo, Long loginId) {
        //保存数据
        User user = new User();
        //设置参数
        user.setCreateTime(new Date());
        user.setNickName(registerVo.getMobile());//昵称 如果是手机号注册 我们可以直接设置为手机号
        user.setPhone(registerVo.getMobile());
        user.setLoginId(loginId);
        //todo 明天讲
        Long bitState = BitStatesUtils.addState(0L, BitStatesUtils.OP_REGISTED);
        bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_ACTIVED);
        bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(bitState);
        user.setSecLevel(0);
        super.save(user);
    }

    private Long saveLogin(RegisterVo registerVo) {
        Login login = new Login();
        //密码加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(registerVo.getPassword());
        login.setPassword(encode);
        login.setUsername(registerVo.getMobile());
        login.setType(registerVo.getRegChannel());
        JsonResult jsonResult = uaaOpenFeign.saveOrUpdate(login);
        if(!jsonResult.getSuccess()){
            throw new GlobalException("系统异常，请联系管理员");
        }
        //注意 ： 我们在使用OpenFeign调用  OpenFeign会自动将  Long 转为  integer
        Long loginId = ((Integer) jsonResult.getData()).longValue();
        return loginId;
    }
}
